1 Introduction

1.1 Text is the new data

PHE produces numerous reports, bulletins, and communications, and receives large amounts of feedback. In recent years the ability to analyse text as data has developed rapidly, and there are now tools which can help us gain insight from documents and bodies of texts. These tools allow us to rapidly analyse large numbers of documents. This note applies some of these techniques to analysing Duncan Selbie’s Friday Messages.

There are a number of steps:

  • Automated downloading all the bulletins (web-scraping)
  • Converting pdf files to text
  • Tidying the data to make it analysable
  • Applying visualisation techniques like word clouds
  • Applying text mining and clustering techniques like topic modelling which can help discover the main themes of the bulletins, and automatically classify them based on these themes.

This analysis is conducted using the statistical package R which is rapidly becoming the main tool for undertaking this kind of analysis.

knitr::opts_chunk$set(echo = FALSE)

First we need to load the libraries for the analysis.

library(knitr)
suppressPackageStartupMessages(library(rvest))
suppressPackageStartupMessages(library(stringr))
suppressPackageStartupMessages(library(dplyr))
suppressPackageStartupMessages(library(httr))
suppressPackageStartupMessages(library(tm))
suppressPackageStartupMessages(library(pdftools))
suppressPackageStartupMessages(library(tidytext))
suppressPackageStartupMessages(library(ggplot2))
library(tidyverse)
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Conflicts with tidy packages -------------------------------------------------------------
annotate(): ggplot2, NLP
content():  httr, NLP
filter():   dplyr, stats
lag():      dplyr, stats
source("~/themejf.R") ## A standard theme for plots

1.2 Downloading messages - web scraping

Then we need to get the data. This process identifies the URLs of the Public Health Matters blog.

## Scraping bulletins
### This is the main stem of the URLs for Public Health Matters Blogs
url <- "https://publichealthmatters.blog.gov.uk/category/duncan-selbie-friday-message/"
page <- read_html(url)
urls <- page %>%
  
  html_nodes("a") %>%       # find all links
  
  html_attr("href")     # get the url
urls <- unique(urls[grepl("friday",urls)])  ## Select those which are friday messages
url_comment <- urls[stringr::str_detect(urls, "comments$")]
url_category <- urls[stringr::str_detect(urls, "category")]
urls <- urls[!urls %in% url_comment]
urls <- urls[!urls %in% url_category]

1.3 We’ll extract the date from the title

1.3.1 Removing ‘stop words’

Stop words are common English words which occur frequently in all documents and are generally removed for analytical purposes. In addition, there are words common to all bulletins which add little value in analysis - we’ll add these to the stop_words lexicon.

1.4 Visualisation

1.4.1 Words per document

We can do some simple analysis.

1.4.2 Simple wordcloud

And wordclouds…

2 Analysis by bulletin

We can extend the anlaysis further by looking at the distribution of terms in individual bulletins, and then looking for patterns to see if bulletins can be clustered according to content.

First we can look at a single bulletin:

text title date1
2 We are a healthy nation and we are living longer and in better health. We are incredibly fortunate to have dynamic local Government leaders, with relentlessly hardworking teams and an unrivalled health system in the NHS. We have achieved so much to be proud of, yet we are still faced with the fact that benefiting from more years in good health is not something shared equally across society.Yesterday, we published our first Health Profile for England, bringing together the wealth of population data that we and our partners collect to give a broad picture of the health of people in England today. We’ve also published an easy-to-read blog, outlining the 10 key messages. A big part of our role at PHE is to provide evidence and interpret data, and while this report captures and showcases what we know in a novel way, it also makes plain that health inequalities remain a major theme. As the new report shows, people in the richest areas of the country are enjoying nearly 20 more years in good health than those living in the poorest.The Health Profile for England reinforces that good public health is influenced by much more than healthcare alone. Health and wellbeing for individuals is greatly increased by having a job, having a roof over your head, being part of a community and receiving and giving support to people you care for and about. We want this to be used as a reference point when policymakers are thinking about the broader impacts on health of public policy across government both local and national, the NHS, employers and the voluntary and third sector. Going forward, we want to work with policy makers, decision makers and practitioners to reach more people, particularly those who are vulnerable, with the interventions that are going to enable them to live healthier and longer lives. I do hope you find this inspiring and concerning in equal order and that you help PHE improve the product for future years.Published today is the Government’s new Drugs Strategy, strongly informed by our comprehensive Drugs Evidence Review, published in January this year. It again emphasises the importance for vulnerable people of having a decent job and housing, along with treatment, as being key to a sustained recovery. In addition, it recognises the need for all parts of the health and social care system to work together to improve drug users’ physical and mental health - often badly damaged by long term use.Drug misuse is a complex issue that does not happen in isolation. The strategy's focus on the close partnerships that are needed to create positive change is timely and it gives a clear leadership role to local authorities on the drug prevention and treatment agenda, and PHE will provide help and support in implementing it.This week we published a resource that looks at ways to assist local government both in reducing children and young people’s risk of child sexual exploitation (CSE) and intervening when it does happen. With the support of the Association of Directors of Public Health and the Children’s Commissioner for England we have set out the evidence and produced a framework through which three key local actions can be taken: lead, understand and act. Please do have a look at this.Another factor affecting your health is the natural and built environment. Working with the University of the West of England, PHE has produced a series of infographics summarising the quality and strength of the evidence concentrating on five key built environment topics, including: neighbourhood design, housing, access to healthier food, natural and sustainable environment, and transport.  Spatial Planning for Health: An evidence resource, is a practical summary for use by local planners, public health teams and local communities to help them develop Local Plans and deliver building projects on the ground which demonstrate the links between good design and health.And finally, on Wednesday evening at Colindale, our scientific campus in North London, a ceremony took place for the first graduates of our employment programme for people with a learning disability and/or who are on the autism spectrum, called Project SEARCH. The average employment rate for individuals aged 18–24 with a learning disability in the UK is just 7%, but for those involved in Project SEARCH, this rises to 65%. I met the students, their families and their PHE mentors during a moving evening, which saw our students leave us with 800 hours under their belt of meaningful work experience, more employability and a BTEC Entry Level Award and Certificate in Work Skills and I could not be more proud of them and our staff. The students will continue to get support from Project SEARCH to move into mainstream employment and we look forward to hearing about their success and welcoming the next class in September. https://publichealthmatters.blog.gov.uk/2017/07/14/duncan-selbies-friday-message-14-july-2017/ 2017-07-14

We can then create a per document per term table known as a Document Term Matrix (DTM). We can count the terms per document.

Next we can create the DTM.

corp_dtm
<<DocumentTermMatrix (documents: 10, terms: 1534)>>
Non-/sparse entries: 2413/12927
Sparsity           : 84%
Maximal term length: 19
Weighting          : term frequency (tf)

2.1 Word associations

We can see which words tend to appear together in the bulletins.

findAssocs(corp_dtm, "sugar", 0.6)
$sugar
     businesses     encouraging       reduction            2020      identified 
           1.00            1.00            1.00            1.00            1.00 
       industry          remove          trusts              14         200,000 
           1.00            1.00            1.00            1.00            1.00 
           2019          accept           acute             add      approaches 
           1.00            1.00            1.00            1.00            1.00 
         atrial        baseline       behaviour         bullied             buy 
           1.00            1.00            1.00            1.00            1.00 
      charities         charity       child.our       childhood          choice 
           1.00            1.00            1.00            1.00            1.00 
  collaborative colleagues.next     commitments       companies       comprises 
           1.00            1.00            1.00            1.00            1.00 
  consultations       consumers     consumption        councils       deadlines 
           1.00            1.00            1.00            1.00            1.00 
        default        delivery          desire            diet      efficiency 
           1.00            1.00            1.00            1.00            1.00 
    emphasising         estates        estimate fibrillation.it     flexibility 
           1.00            1.00            1.00            1.00            1.00 
          foods            gaps        genetics      guidelines       instilled 
           1.00            1.00            1.00            1.00            1.00 
          joint           lower       maintains   march.obesity           meals 
           1.00            1.00            1.00            1.00            1.00 
      milestone            mind         month’s           obese       ordinated 
           1.00            1.00            1.00            1.00            1.00 
     originally         outlets          parent         players       portfolio 
           1.00            1.00            1.00            1.00            1.00 
       portions       providers             pub            quit   reformulation 
           1.00            1.00            1.00            1.00            1.00 
    restaurants        richmond            rise     staff.doing         subject 
           1.00            1.00            1.00            1.00            1.00 
      takeaways        template          tonnes      undeniable        uniquely 
           1.00            1.00            1.00            1.00            1.00 
       untapped            view        visitors         website            food 
           1.00            1.00            1.00            1.00            0.99 
        obesity           smoke            stay             gap            home 
           0.95            0.95            0.88            0.87            0.85 
      voluntary        partners            free       healthier         leading 
           0.85            0.80            0.78            0.75            0.75 
    environment            2017       potential      contribute        products 
           0.67            0.67            0.67            0.67            0.67 
        quickly           scale     significant             100            2016 
           0.67            0.67            0.67            0.67            0.67 
          blogs         british  cardiovascular      charitable         choices 
           0.67            0.67            0.67            0.67            0.67 
     commitment         complex      confidence         develop          eating 
           0.67            0.67            0.67            0.67            0.67 
     emphasises       expanding         focuses    government’s      initiative 
           0.67            0.67            0.67            0.67            0.67 
   intervention           leave        outlines      overweight         playing 
           0.67            0.67            0.67            0.67            0.67 
       progress     publication         reality         sectors         setting 
           0.67            0.67            0.67            0.67            0.67 
          slide           steps         studies          taking      unrivalled 
           0.67            0.67            0.67            0.67            0.67 
         unwell           video            care 
           0.67            0.67            0.61 

And the next step is topic modelling - this allows us to analyse the whole body of bulletins and look for themes or topics - groupings of words within and between documents.

corp_lda
A LDA_VEM topic model with 6 topics.
corp_lda_tidy <- tidy(corp_lda)
corp_lda_tidy %>%
  group_by(topic) %>%
  top_n(20, beta) %>%
  ungroup() %>%
  arrange(topic, -beta) %>%
  ggplot(aes(term, beta, fill = factor(topic), label = term)) +
  geom_bar(stat = "identity") +
  geom_text(hjust = 0, size = 10) +
  coord_flip() +
  facet_wrap(~topic, ncol =4) +
  theme_jf() +
  labs(fill = "Topic")

NA
NA
corp_lda_tidy %>%
  group_by(topic) %>%
  top_n(20, beta) %>%
  ungroup() %>%
  arrange(topic, -beta) %>%
  ggplot(aes(term, beta, fill = factor(topic))) +
  geom_point(aes(colour = factor(topic))) +
  geom_line(aes(group = topic)) +
  coord_polar() +
  facet_wrap(~topic, ncol = 4) +
  theme(legend.position = "") +
  theme(axis.text.x = element_text(size = 12))

NA

2.1.1 Classifying documents

LS0tCnRpdGxlOiAiVGV4dCBtaW5pbmcgUEhFJ3MgYmxvZ3MiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCiMgSW50cm9kdWN0aW9uCgojIyBUZXh0IGlzIHRoZSBuZXcgZGF0YQoKUEhFIHByb2R1Y2VzIG51bWVyb3VzIHJlcG9ydHMsIGJ1bGxldGlucywgYW5kIGNvbW11bmljYXRpb25zLCBhbmQgcmVjZWl2ZXMgbGFyZ2UgYW1vdW50cyBvZiBmZWVkYmFjay4gSW4gcmVjZW50IHllYXJzIHRoZSBhYmlsaXR5IHRvIGFuYWx5c2UgdGV4dCBhcyBkYXRhIGhhcyBkZXZlbG9wZWQgcmFwaWRseSwgYW5kIHRoZXJlIGFyZSBub3cgdG9vbHMgd2hpY2ggY2FuIGhlbHAgdXMgZ2FpbiBpbnNpZ2h0IGZyb20gZG9jdW1lbnRzIGFuZCBib2RpZXMgb2YgdGV4dHMuIFRoZXNlIHRvb2xzIGFsbG93IHVzIHRvIHJhcGlkbHkgYW5hbHlzZSBsYXJnZSBudW1iZXJzIG9mIGRvY3VtZW50cy4gVGhpcyBub3RlIGFwcGxpZXMgc29tZSBvZiB0aGVzZSB0ZWNobmlxdWVzIHRvIGFuYWx5c2luZyBEdW5jYW4gU2VsYmllJ3MgRnJpZGF5IE1lc3NhZ2VzLgoKVGhlcmUgYXJlIGEgbnVtYmVyIG9mIHN0ZXBzOgoKKiBBdXRvbWF0ZWQgZG93bmxvYWRpbmcgYWxsIHRoZSBidWxsZXRpbnMgKHdlYi1zY3JhcGluZykKKiBDb252ZXJ0aW5nIHBkZiBmaWxlcyB0byB0ZXh0CiogVGlkeWluZyB0aGUgZGF0YSB0byBtYWtlIGl0IGFuYWx5c2FibGUKKiBBcHBseWluZyB2aXN1YWxpc2F0aW9uIHRlY2huaXF1ZXMgbGlrZSB3b3JkIGNsb3VkcwoqIEFwcGx5aW5nIHRleHQgbWluaW5nIGFuZCBjbHVzdGVyaW5nIHRlY2huaXF1ZXMgbGlrZSB0b3BpYyBtb2RlbGxpbmcgd2hpY2ggY2FuIGhlbHAgZGlzY292ZXIgdGhlIG1haW4gdGhlbWVzIG9mIHRoZSBidWxsZXRpbnMsIGFuZCBhdXRvbWF0aWNhbGx5IGNsYXNzaWZ5IHRoZW0gYmFzZWQgb24gdGhlc2UgdGhlbWVzLgoKVGhpcyBhbmFseXNpcyBpcyBjb25kdWN0ZWQgdXNpbmcgdGhlIHN0YXRpc3RpY2FsIHBhY2thZ2UgYFJgIHdoaWNoIGlzIHJhcGlkbHkgYmVjb21pbmcgdGhlIG1haW4gdG9vbCBmb3IgdW5kZXJ0YWtpbmcgdGhpcyBraW5kIG9mIGFuYWx5c2lzLgoKYGBge3Igc2V0dXAsIGNhY2hlPVRSVUV9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gRkFMU0UpCgpgYGAKCkZpcnN0IHdlIG5lZWQgdG8gbG9hZCB0aGUgbGlicmFyaWVzIGZvciB0aGUgYW5hbHlzaXMuCgpgYGB7ciBsb2FkIGxpYnJhcmllc30KbGlicmFyeShrbml0cikKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkocnZlc3QpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShzdHJpbmdyKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoZHBseXIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShodHRyKSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkodG0pKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeShwZGZ0b29scykpCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KHRpZHl0ZXh0KSkKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoZ2dwbG90MikpCmxpYnJhcnkodGlkeXZlcnNlKQoKc291cmNlKCJ+L3RoZW1lamYuUiIpICMjIEEgc3RhbmRhcmQgdGhlbWUgZm9yIHBsb3RzCmBgYAoKIyMgRG93bmxvYWRpbmcgbWVzc2FnZXMgLSB3ZWIgc2NyYXBpbmcKClRoZW4gd2UgbmVlZCB0byBnZXQgdGhlIGRhdGEuIFRoaXMgcHJvY2VzcyBpZGVudGlmaWVzIHRoZSBVUkxzIG9mIHRoZSBQdWJsaWMgSGVhbHRoIE1hdHRlcnMgYmxvZy4KCgpgYGB7ciBJZGVudGlmeSBVUkxzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBjYWNoZT1UUlVFfQoKCiMjIFNjcmFwaW5nIGJ1bGxldGlucwoKCgojIyMgVGhpcyBpcyB0aGUgbWFpbiBzdGVtIG9mIHRoZSBVUkxzIGZvciBQdWJsaWMgSGVhbHRoIE1hdHRlcnMgQmxvZ3MKdXJsIDwtICJodHRwczovL3B1YmxpY2hlYWx0aG1hdHRlcnMuYmxvZy5nb3YudWsvY2F0ZWdvcnkvZHVuY2FuLXNlbGJpZS1mcmlkYXktbWVzc2FnZS8iCgpwYWdlIDwtIHJlYWRfaHRtbCh1cmwpCgp1cmxzIDwtIHBhZ2UgJT4lCiAgCiAgaHRtbF9ub2RlcygiYSIpICU+JSAgICAgICAjIGZpbmQgYWxsIGxpbmtzCiAgCiAgaHRtbF9hdHRyKCJocmVmIikgICAgICMgZ2V0IHRoZSB1cmwKCnVybHMgPC0gdW5pcXVlKHVybHNbZ3JlcGwoImZyaWRheSIsdXJscyldKSAgIyMgU2VsZWN0IHRob3NlIHdoaWNoIGFyZSBmcmlkYXkgbWVzc2FnZXMKdXJsX2NvbW1lbnQgPC0gdXJsc1tzdHJpbmdyOjpzdHJfZGV0ZWN0KHVybHMsICJjb21tZW50cyQiKV0KdXJsX2NhdGVnb3J5IDwtIHVybHNbc3RyaW5ncjo6c3RyX2RldGVjdCh1cmxzLCAiY2F0ZWdvcnkiKV0KCnVybHMgPC0gdXJsc1shdXJscyAlaW4lIHVybF9jb21tZW50XQp1cmxzIDwtIHVybHNbIXVybHMgJWluJSB1cmxfY2F0ZWdvcnldCgpgYGAKCgoKYGBge3IgRXh0cmFjdCB0ZXh0IGFuZCBjcmVhdGUgZGF0YSBmcmFtZX0KZGYgPC0gZGF0YS5mcmFtZSgpCmZvcih1cmwgaW4gdXJscyl7Cgp0ZXN0MSA8LSByZWFkX2h0bWwodXJsKSAlPiUgCiAgaHRtbF9ub2RlcygicCIpCgoKCnRlc3QyIDwtIGh0bWxfdGV4dCh0ZXN0MSkgJT4lCiAgc3RyX3JlcGxhY2VfYWxsKCJcbiIsICIiKQoKIyMgUmVtb3ZlIDFzdCByb3cKdGVzdDIgPC0gdGVzdDJbMjpsZW5ndGgodGVzdDIpXQoKIyMgRXh0cmFjdCB0aXRsZQoKdGl0bGUgPC0gdGVzdDJbMV0KCiMjIEV4dHJhY3QgYm9keSB0ZXh0Cgp0ZXh0IDwtIHRlc3QyWzU6bGVuZ3RoKHRlc3QyKV0KCnRleHQgPC0gc3RyX2ModGV4dCwgY29sbGFwc2UgPSAiIikKCiMjIENsZWFuIGVuZCBtYXR0ZXIKCgp0ZXN0MyA8LSBnc3ViKCJXaXRoIGJlc3Qgd2lzaGVzLioiLCAiIiwgdGV4dCApCgp0ZXN0NCA8LSBkYXRhLmZyYW1lKHRlc3QzLCB0aXRsZSkKCmRmIDwtIGJpbmRfcm93cyhkZiwgdGVzdDQpCgp9CgpgYGAKCgojIyBXZSdsbCBleHRyYWN0IHRoZSBkYXRlIGZyb20gdGhlIHRpdGxlCgpgYGB7cn0KCmRhdGUgPC0gc3RyaW5ncjo6c3RyX3NwbGl0KGRmJHRpdGxlLCBwYXR0ZXJuID0gIi8iKQoKeWVhciA8LSBtYXAoZGF0ZSwgIDQpCm1vbnRoIDwtIG1hcChkYXRlLCA1KQpkYXkgPC0gbWFwKGRhdGUsIDYpCgpkYXRlMSA8LSBwYXN0ZSh5ZWFyLCBtb250aCwgZGF5LCBzZXAgPSAiLSIpCgpkZiA8LSBjYmluZChkZiwgZGF0ZTEpCgpkZiRkYXRlMSA8LSBhcy5EYXRlKGFzLmNoYXJhY3RlcihkZiRkYXRlMSkpCgpkZiA8LSByZW5hbWUoZGYsIAogICAgICAgICAgICAgdGV4dCA9IHRlc3QzKQoKCmBgYAoKCgojIyMgUmVtb3ZpbmcgJ3N0b3Agd29yZHMnCgpTdG9wIHdvcmRzIGFyZSBjb21tb24gRW5nbGlzaCB3b3JkcyB3aGljaCBvY2N1ciBmcmVxdWVudGx5IGluIGFsbCBkb2N1bWVudHMgYW5kIGFyZSBnZW5lcmFsbHkgcmVtb3ZlZCBmb3IgYW5hbHl0aWNhbCBwdXJwb3Nlcy4gSW4gYWRkaXRpb24sIHRoZXJlIGFyZSB3b3JkcyBjb21tb24gdG8gYWxsIGJ1bGxldGlucyB3aGljaCBhZGQgbGl0dGxlIHZhbHVlIGluIGFuYWx5c2lzIC0gd2UnbGwgYWRkIHRoZXNlIHRvIHRoZSBgc3RvcF93b3Jkc2AgbGV4aWNvbi4KCmBgYHtyfQoKCmJ1bGxldGluX3N3IDwtIGRhdGFfZnJhbWUod29yZCA9IGMoInBoZSIsImZyaWRheSIsICJkZWFyIiwgIndlZWsiLCAiaGVhbHRoIiwgInB1Ymxpc2hlZCIsICJidWxsZXRpbiIsICJwcmVzcyIsICJwdWJsaWMiLCAicGhlJ3MiLCAid3d3Lmdvdi51ayIsICJuZXdzIiwgInB1YmxpY2F0aW9ucyIsICJnYXRld2F5IiwgImZvcm1vcmUiKSwgbGV4aWNvbiA9ICJTTUFSVCIgKQoKc3RvcF93b3JkczEgPC0gYmluZF9yb3dzKHN0b3Bfd29yZHMsIGJ1bGxldGluX3N3KQpgYGAKCgojIyBWaXN1YWxpc2F0aW9uCgojIyMgV29yZHMgcGVyIGRvY3VtZW50CgpXZSBjYW4gZG8gc29tZSBzaW1wbGUgYW5hbHlzaXMuCgpgYGB7ciwgZmlnLmhlaWdodD02LCBjYWNoZT1UUlVFfQpkZiAlPiUgCiAgZ3JvdXBfYnkoZGF0ZTEpICU+JSAKICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQpICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSU+JQogIHN1bW1hcmlzZSh3b3JkcyA9IHN1bShuKSkgJT4lCiAgZ2dwbG90KGFlcyhyZW9yZGVyKGRhdGUxLCB3b3JkcyksIHdvcmRzKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHg9IiIsIAogICAgICAgeSA9ICJOdW1iZXIgb2Ygd29yZHMiLAogICAgICAgdGl0bGUgPSAiTnVtYmVyIG9mIHdvcmRzIHBlciBibG9nIikgKwogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgID0gMTApKQpgYGAKCgojIyMgU2ltcGxlIHdvcmRjbG91ZAoKQW5kIHdvcmRjbG91ZHMuLi4KIApgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgY2FjaGU9VFJVRX0KbGlicmFyeSh3b3JkY2xvdWQpCgpjbG91ZCA8LSBkZiAlPiUgCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KSAlPiUKICBhbnRpX2pvaW4oc3RvcF93b3JkczEpICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKQoKd2l0aChjbG91ZCwgd29yZGNsb3VkKHdvcmQsIG4sIG1heC53b3JkcyA9ICdJTkYnLCBzY2FsZSA9IGMoOCwgMC4yKSwgCiAgICAgICAgICAgICAgICAgICAgICByb3QucGVyID0gMC40LCByYW5kb20ub3JkZXIgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICBjb2xvcnMgPSBicmV3ZXIucGFsKDgsICJEYXJrMiIpKSkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OH0KbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkodGlkeXIpCgpwYWw8LSBicmV3ZXIucGFsKDExLCJTcGVjdHJhbCIpCgpjbG91ZDEgPC0gZGYgJT4lIAogIHVubmVzdF90b2tlbnMoYmlncmFtLCB0ZXh0LCB0b2tlbiA9ICJuZ3JhbXMiLCBuID0gMikgJT4lCiAgY291bnQoYmlncmFtLCBzb3J0ID0gVFJVRSkKCgojIyBTcGxpdCB0aGUgYmlncmFtcyBiYWNrIGludG8gc2VwYXJhdGUgd29yZHMKY2xvdWRfc2VwIDwtIGNsb3VkMSAlPiUKICBzZXBhcmF0ZShiaWdyYW0sIGMoIndvcmQxIiwgIndvcmQyIiksIHNlcCA9ICIgIikgCgoKIyMgYW5kIGZpbHRlciBvdXQgdGhlICdzdG9wIHdvcmRzJwoKY2xvdWRfZmlsdCA8LSBjbG91ZF9zZXAgJT4lCiAgZmlsdGVyKCF3b3JkMSAlaW4lIHN0b3Bfd29yZHMxJHdvcmQpICU+JQogIGZpbHRlcighd29yZDIgJWluJSBzdG9wX3dvcmRzMSR3b3JkKQogIAojIyBhbmQgcmVjb21iaW5lCgpjbG91ZF9uZXcgPC0gY2xvdWRfZmlsdCAlPiUKICB1bml0ZShiaWdyYW0sIHdvcmQxLCB3b3JkMiwgc2VwID0gIiAiKQoKY2xvdWRfbmV3IAojIyBhbmQgcmVwbG90IHRoZSB3b3JkIGNsb3VkICAKd2l0aChjbG91ZF9uZXcsIHdvcmRjbG91ZChiaWdyYW0sIG4sIG1heC53b3JkcyA9IEluZiwgcmFuZG9tLm9yZGVyID0gRkFMU0UsIHJhbmRvbS5jb2xvciA9IEZBTFNFLCBzY2FsZSA9IGMoOCwgMC4zKSwgcm90LnBlciA9IC4zLCBjb2xvcnMgPSBwYWwpKQoKYGBgCgoKCiMgQW5hbHlzaXMgYnkgYnVsbGV0aW4KCldlIGNhbiBleHRlbmQgdGhlIGFubGF5c2lzIGZ1cnRoZXIgYnkgbG9va2luZyBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRlcm1zIGluIGluZGl2aWR1YWwgYnVsbGV0aW5zLCBhbmQgdGhlbiBsb29raW5nIGZvciBwYXR0ZXJucyB0byBzZWUgaWYgYnVsbGV0aW5zIGNhbiBiZSBjbHVzdGVyZWQgYWNjb3JkaW5nIHRvIGNvbnRlbnQuCgpGaXJzdCB3ZSBjYW4gbG9vayBhdCBhIHNpbmdsZSBidWxsZXRpbjoKCmBgYHtyfQpkZiU+JQogIHNhbXBsZV9uKDEpICU+JQogIGtuaXRyOjprYWJsZShmb3JtYXQgPSAicGFuZG9jIikKYGBgCgpXZSBjYW4gdGhlbiBjcmVhdGUgYSBwZXIgZG9jdW1lbnQgcGVyIHRlcm0gdGFibGUga25vd24gYXMgYSBEb2N1bWVudCBUZXJtIE1hdHJpeCAoRFRNKS4gV2UgY2FuIGNvdW50IHRoZSB0ZXJtcyBwZXIgZG9jdW1lbnQuCgpgYGB7cn0KY29ycF9kdG0gPC0gZGYgJT4lCiAgZ3JvdXBfYnkoZGF0ZTEpICU+JQogIHVubmVzdF90b2tlbnMod29yZCwgdGV4dCkgJT4lCiAgYW50aV9qb2luKHN0b3Bfd29yZHMxKSAlPiUKICBjb3VudChkYXRlMSwgd29yZCwgc29ydCA9IFRSVUUpIAoKY29ycF9kdG0KYGBgCgpOZXh0IHdlIGNhbiBjcmVhdGUgdGhlIERUTS4KCmBgYHtyfQpjb3JwX2R0bSA8LSBjb3JwX2R0bSAlPiUKICBjYXN0X2R0bShkYXRlMSwgd29yZCwgbikKCmNvcnBfZHRtCiAgCmBgYAoKCiMjIFdvcmQgYXNzb2NpYXRpb25zIAoKV2UgY2FuIHNlZSB3aGljaCB3b3JkcyB0ZW5kIHRvIGFwcGVhciB0b2dldGhlciBpbiB0aGUgYnVsbGV0aW5zLgoKYGBge3IgYXNzb2NpYXRpb25zfQojIyBGb3IgZXhhbXBsZS4uLgoKIyMjIEFsY29ob2wKCmZpbmRBc3NvY3MoY29ycF9kdG0sICJhbGNvaG9sIiwgMC43NSkKCiMjIyBTdWdhcgoKZmluZEFzc29jcyhjb3JwX2R0bSwgInN1Z2FyIiwgMC42KQpgYGAKCgoKQW5kIHRoZSBuZXh0IHN0ZXAgaXMgdG9waWMgbW9kZWxsaW5nICAtIHRoaXMgYWxsb3dzIHVzIHRvIGFuYWx5c2UgdGhlIHdob2xlIGJvZHkgb2YgYnVsbGV0aW5zIGFuZCBsb29rIGZvciB0aGVtZXMgb3IgdG9waWNzIC0gZ3JvdXBpbmdzIG9mIHdvcmRzIHdpdGhpbiBhbmQgYmV0d2VlbiBkb2N1bWVudHMuCgpgYGB7cn0KbGlicmFyeSh0b3BpY21vZGVscykKCmNvcnBfbGRhIDwtIExEQShjb3JwX2R0bSwgayA9IDYsIGNvbnRyb2wgPSBsaXN0KHNlZWQgPSAxMjM0KSkKY29ycF9sZGEKCmBgYAoKCmBgYHtyfQpjb3JwX2xkYV90aWR5IDwtIHRpZHkoY29ycF9sZGEpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9MTJ9CmNvcnBfbGRhX3RpZHkgJT4lCiAgZ3JvdXBfYnkodG9waWMpICU+JQogIHRvcF9uKDIwLCBiZXRhKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXJyYW5nZSh0b3BpYywgLWJldGEpICU+JQogIGdncGxvdChhZXModGVybSwgYmV0YSwgZmlsbCA9IGZhY3Rvcih0b3BpYyksIGxhYmVsID0gdGVybSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdlb21fdGV4dChoanVzdCA9IDAsIHNpemUgPSAxMCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgZmFjZXRfd3JhcCh+dG9waWMsIG5jb2wgPTQpICsKICB0aGVtZV9qZigpICsKICBsYWJzKGZpbGwgPSAiVG9waWMiKQogIAogIApgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD0xMn0KY29ycF9sZGFfdGlkeSAlPiUKICBncm91cF9ieSh0b3BpYykgJT4lCiAgdG9wX24oMjAsIGJldGEpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKHRvcGljLCAtYmV0YSkgJT4lCiAgZ2dwbG90KGFlcyh0ZXJtLCBiZXRhLCBmaWxsID0gZmFjdG9yKHRvcGljKSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBmYWN0b3IodG9waWMpKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSB0b3BpYykpICsKICBjb29yZF9wb2xhcigpICsKICBmYWNldF93cmFwKH50b3BpYywgbmNvbCA9IDQpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiIikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpCiAgCmBgYAoKIyMjIENsYXNzaWZ5aW5nIGRvY3VtZW50cwoKYGBge3IgZG9jdW1lbnQgY2xhc3NpZmljYXRpb259CmxkYV9nYW1tYSA8LSB0aWR5dGV4dDo6OnRpZHkuTERBKGNvcnBfbGRhLCBtYXRyaXggPSAiZ2FtbWEiKQoKbGRhX2dhbW1hCgphYnNfY2xhc3MgPC0gbGRhX2dhbW1hICU+JQogIGdyb3VwX2J5KGRvY3VtZW50KSAlPiUKICB0b3BfbigxLCBnYW1tYSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGFycmFuZ2UoZ2FtbWEpCgphYnNfY2xhc3MKCmFic19jbGFzcyAlPiUKICBncm91cF9ieSh0b3BpYykgJT4lCiAgY291bnQoKQoKYWJzX2NsYXNzICU+JQogIGdncGxvdChhZXMobHVicmlkYXRlOjp5bWQoZG9jdW1lbnQpLCBhcy5mYWN0b3IodG9waWMpLCBsYWJlbCA9IGRvY3VtZW50KSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IHRvcGljKSkgKwogIGdlb21fcGF0aChhZXMoY29sb3VyID0gdG9waWMpKSsKICBnZW9tX3RleHQoc2l6ZSA9IDIsIGFuZ2xlID0gNDUsIGhqdXN0ID0gMCwgdmp1c3QgPSAwKSsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgOSkpICsKICBsYWJzKHkgPSAiVG9waWMgbnVtYmVyIiApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiIikKICAKCgpgYGAKCg==